import selectors
import socket

from FPDLCore import Configs


class BaseServerNet:

    def __init__(self, port):
        self.port = port

    def start(self):
        def accept(sock, mask):
            conn, addr = sock.accept()
            print('accepted', conn, 'from', addr)
            conn.setblocking(False)
            self.sel.register(conn, selectors.EVENT_READ, self._read)
            self.onaccepted(conn)

        def read(conn, mask):
            try:
                data = conn.recv(Configs.RECIVE_BUFFER_SIZE)
            except ConnectionError as e:
                print("on event read", conn, e)
                data = None
            if data:
                self.onread(conn, data)
            else:
                self.close(conn)

        def send(conn, mask):
            try:
                self.onsend(conn)
            except ConnectionError as e:
                print("on event send", conn, e)
                self.close(conn)

        self._accept = accept
        self._read = read
        self._send = send
        try:
            self.sel = selectors.DefaultSelector()
            self.sock = socket.socket()
            self.sock.bind(('0.0.0.0', self.port))
            self.sock.listen(100)
            self.sock.setblocking(False)
            self.sel.register(self.sock, selectors.EVENT_READ, self._accept)
        except Exception as e:
            print(e)
            return

        self.onstart()

        while True:
            events = self.sel.select()
            for key, mask in events:
                callback = key.data
                callback(key.fileobj, mask)

        self.onexit()

    def close(self, conn):
        print('close', conn)
        self.onclose(conn)
        conn.close()
        self.sel.unregister(conn)

    def onstart(self):
        pass

    def onexit(self):
        pass

    def onaccepted(self, conn):
        pass

    def onread(self, conn, data):
        pass

    def onsend(self, conn):
        pass

    def onclose(self, conn):
        pass

    def waitread(self, conn):
        self.sel.modify(conn, selectors.EVENT_READ, self._read)

    def waitsend(self, conn):
        self.sel.modify(conn, selectors.EVENT_WRITE, self._send)
